using SPI.AgentServer.Models;

namespace SPI.AgentServer.Services.Tools;

public class ToolExecutor : IToolExecutor
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ILogger<ToolExecutor> _logger;
    private readonly Dictionary<string, IQueryTool> _tools;

    public ToolExecutor(IServiceProvider serviceProvider, ILogger<ToolExecutor> logger, IEnumerable<IQueryTool> tools)
    {
        _serviceProvider = serviceProvider;
        _logger = logger;
        _tools = tools.ToDictionary(t => t.Name, t => t);
    }

    public async Task<ToolResult> ExecuteToolAsync(ToolInstruction instruction, CancellationToken cancellationToken = default)
    {
        try
        {
            var tool = GetTool(instruction.Tool);
            
            if (tool == null)
            {
                return new ToolResult
                {
                    Success = false,
                    Errors = new List<string> { $"Tool '{instruction.Tool}' not found" }
                };
            }

            _logger.LogInformation("Executing tool: {ToolName} with parameters: {Parameters}", 
                instruction.Tool, instruction.Parameters);

            var result = await tool.ExecuteAsync(instruction.Parameters, cancellationToken);

            if (result.Success)
            {
                _logger.LogInformation("Tool {ToolName} executed successfully", instruction.Tool);
            }
            else
            {
                _logger.LogWarning("Tool {ToolName} failed: {Errors}", 
                    instruction.Tool, string.Join(", ", result.Errors));
            }

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error executing tool: {ToolName}", instruction.Tool);
            return new ToolResult
            {
                Success = false,
                Errors = new List<string> { $"Tool execution error: {ex.Message}" }
            };
        }
    }

    public IQueryTool? GetTool(string toolName)
    {
        return _tools.TryGetValue(toolName, out var tool) ? tool : null;
    }

    public List<string> GetAvailableToolNames()
    {
        return _tools.Keys.ToList();
    }
}
